/**
 * The Woosta Table Football Engine
 *
 * License... etc.
 **
 * Physics Engine - NO physics
 **
 * Author: Sean Micklethwaite
 **/

#ifndef __physics_noneH__
#define __physics_noneH__

#ifndef __RENDER_WORLD_OBJECT__
#	define __RENDER_WORLD_OBJECT__
#endif

#include "dynamic.h"
#include "render.h"
#include "3d.h"



namespace WtfEngine 
{
	class PhysicalModel : public DataObject
	{
		public:
			typedef GcReference<PhysicalModel> tRef;

			PhysicalModel() {};
			~PhysicalModel() {};

			tScalar getMassQuot() const{
				return 0;
			};
	};

	/**** Forward Declarations ****/

	class Static;
	class Physical;

	
	class ObjectConnectionEvent : public ObjectInteractionEvent
	{
		tPosition	vPosition;
		
		public:
			ObjectConnectionEvent(GameObject *pConnector, GameObject *pConnectee, const tPosition& pos)
			: ObjectInteractionEvent(pConnector, pConnectee), vPosition(pos){
			};
		
			const tPosition& getPosition(){
				return vPosition;
			};
	};
	
	class ObjectDisconnectionEvent : public ObjectInteractionEvent
	{
		public:
			ObjectDisconnectionEvent(GameObject *pConnector, GameObject *pConnectee)
			: ObjectInteractionEvent(pConnector, pConnectee){
			};
	};
	
	
	/**
	 * A class representing a group of connected physical & static objects,
	 * each connected in a pairwise fashion via a 'Connection'.
	 * The system is resolved before object update, in order to balance
	 * the internal forces based upon the external forces acting upon the
	 * system.
	 *
	 * This class provides the basis for all rigid body dynamics.
	 **/
	class PhysicalSystem : public GcObject
	{
		virtual ~PhysicalSystem() {};
	};
	
	
	class WorldObject : public Renderable
	{
	protected:
		PhysicalModel::tRef		mModel;
		tPosition				mPosition;
		Orientation3D			mOrientation;
		
	public:
		WorldObject(const tGameObjectCreationArgs& args,
					const WtfGraphics::GraphicsData::tRef& d,
					const PhysicalModel::tRef& m)
			: Renderable(args, d), mModel(m) {};
		virtual ~WorldObject() {};
		
		// Override default Render()
		virtual void Render();
		virtual void Destroy();
		
		void setPosition(tVector pos) {
			mPosition = pos;
		}
		void setOrientation(Orientation3D ori) {
			mOrientation = ori;
		}

		tVector getPosition() {
			return mPosition;
		}
		Orientation3D getOrientation() {
			return mOrientation;
		}
		
		tVector getRotation() {
			return tVector(); // TODO?
		}
		void setRotation(tVector rot) {
			// TODO?
		}
		
		GC_OBJECT(WorldObject, sizeof(WorldObject));
	};
	
	class Physical : public WorldObject
	{
		public:
			typedef GcReference<Physical>	tRef;

			struct Force : public GcObject, public tVector
			{
				typedef GcReference<Force>	tRef;

				tVector		relativePosition;
				tGameTime	remainingTime;

				Force()
					: tVector(), relativePosition() {};
				Force(const tVector& f)
					: tVector(f), relativePosition() {};
				Force(const tVector& f, const tVector& p)
					: tVector(f), relativePosition(p) {};
			};
			
			Physical(const tGameObjectCreationArgs& args,
					 const WtfGraphics::GraphicsData::tRef& d,
					 const PhysicalModel::tRef& m, bool isParticle = false):
				WorldObject(args, d, m) {};
			virtual ~Physical() {};

			void applyForce(tVector force, tVector pos){
			};
			
			void applyForce(const Force::tRef& force) {
			};
			void applyImpulse(tVector impulse, tVector point) {
			};

			const tVector getVelocity() const {
				return tVector();
			};
			const tVector getResultantForce() const {
				return tVector();
			};
			tVector getAcceleration() const {
				return tVector();
			};
			tScalar	getMassQuot() const{
				return 0;
			};

			bool hasPhysicalSystem() const{
				return false;
			};
			void setPhysicalSystem(PhysicalSystem* pSys){
			};
			PhysicalSystem*	getPhysicalSystem() const{
				return NULL;
			};

			void setActive() {
			};
		
			void setVelocity(const tVector& v) {
			};
			void setAngularMomentum(const tVector& mom){
			};

			const PhysicalModel& getModel() const {
				return *mModel;
			};
	};

	/**
	 * Represents a non-movable object
	 **/
	class Static : public WorldObject
	{
		public:
			Static(const tGameObjectCreationArgs& args,
				   const WtfGraphics::GraphicsData::tRef& d,
				   const PhysicalModel::tRef& m): WorldObject(args, d, m) {};
			virtual ~Static() {};

		GC_AUTOSIZE(Static);
	};

	
	/**** Constraints: Allow construction of rigid body systems ****/
	
	class Constraint : public GcObject
	{
		protected:
			Constraint() {};
		public:
			virtual ~Constraint() {};
			
			GC_AUTOSIZE(Constraint);
	};
	
	class PointConstraint : public Constraint
	{
		public:
			PointConstraint(const WorldObject::tRef& o1, const WorldObject::tRef& o2,
				const tPosition& p1, const tPosition& p2) {};
			
			GC_AUTOSIZE(PointConstraint);
	};
	
	class HingeConstraint : public Constraint
	{
		public:
			GC_AUTOSIZE(HingeConstraint);
	};
	
	class SocketConstraint : public Constraint
	{
		public:
			GC_AUTOSIZE(SocketConstraint);
	};
	
	class SliderConstraint : public Constraint
	{
		public:
			SliderConstraint(const WorldObject::tRef& o1, const WorldObject::tRef& o2,
							  const tPosition& p1, const tPosition& p2,
							  const tVector& minLinear, const tVector& maxLinear) {};
			
			GC_AUTOSIZE(SliderConstraint);
	};
	
	
	/**
	 * Fired when two objects collide.
	 **/
	class ObjectCollisionEvent : public ObjectInteractionEvent
	{
		public:
			ObjectCollisionEvent(GameObject * pObj, GameObject * pIntObj)
			: ObjectInteractionEvent(pObj, pIntObj) {};
		
			virtual bool Accepts (const Event& ev){
				const ObjectCollisionEvent*	pEv = dynamic_cast<const ObjectCollisionEvent*>(&ev);
				return ((pEv != NULL) && this->ObjectInteractionEvent::Accepts(ev));
			};
	};
	
	class CollisionDetection : public Task<CollisionDetection>
	{
		public:
			CollisionDetection()
			: Task<CollisionDetection>(500, "CollisionDetection"){};
			~CollisionDetection() {};

		protected:
			void Run() {};
	};

	class PhysicsEngine : public Task<PhysicsEngine>
	{
		std::list<WorldObject::tRef>	mObjects;
		
		public:
			PhysicsEngine(): Task<PhysicsEngine>(0, "Physics Engine (null)") {};
			~PhysicsEngine() {};

			inline void PushPhysical(Physical::tRef pObj) {
				mObjects.push_back(pObj);
			};

			inline void RemovePhysical(Physical::tRef rObj) {
				mObjects.remove(rObj);
			};
		
			inline void PushStatic(Static::tRef pObj) {
				mObjects.push_back(pObj);
			};

			inline void RemoveStatic(Static::tRef rObj) {
				mObjects.remove(rObj);
			};
		
			inline void SetActive(const Physical::tRef& pObj) {
				
			};

			inline void SetPassive(const Physical::tRef& pObj) {
				
			};
			

		protected:
			void Run() {};
	}; 
};


#endif
